package com.geneqiao.jdbc.util;

import java.lang.reflect.Field;
import java.sql.ResultSet;
import java.sql.ResultSetMetaData;
import java.sql.SQLException;
import java.sql.Timestamp;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;

import org.apache.log4j.Logger;

import com.geneqiao.jdbc.jpa.ReflectJPA;
import com.geneqiao.jdbc.jpa.TableStruct;

public class DataUtils<T>
{

	// 日志
	private static final Logger logger = Logger.getLogger(DataUtils.class);

	public static Date getDate(Timestamp timestamp)
	{
		if (timestamp != null) { return new Date(timestamp.getTime()); }
		return null;
	}

	public static String getTimestamp(Timestamp timestamp)
	{
		if (timestamp != null)
		{
			Date date = new Date(timestamp.getTime());
			DateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
			return sdf.format(date);
		}
		return null;
	}

	public static <T> T copyValue(Map<Integer, String> map, ResultSet resultSet, Class<T> t)
	{
		try
		{
			T tt = t.newInstance();
			Set<Integer> keys = map.keySet();
			Field field = null;
			Object obj = null;
			for (Integer key : keys)
			{
				field = DataUtils.getDeclaredField(t, map.get(key));
				if (field == null)
					continue;
				field.setAccessible(true);
				obj = resultSet.getObject(key);
				field.set(tt, ConvertValue(field.getGenericType().toString(), obj));
			}
			return tt;
		}
		catch (Exception e)
		{
			logger.error("数据库对象转换失败,传入对象 => " + t.getClass().getName(), e);
		}
		return null;
	}

	private static Field getDeclaredField(Class<?> t, String name)
	{
		try
		{
			return t.getDeclaredField(name);
		}
		catch (Exception e)
		{
			return getDeclaredField(t.getSuperclass(), name);
		}
	}

	private static Object ConvertValue(String genericType, Object obj)
	{
		if (obj != null)
		{
			// 如果数据库裂隙为Timestamp
			if (obj instanceof Timestamp)
			{
				// logger.info(field.getGenericType());
				if ("class java.util.Date".equals(genericType)) { return getDate((Timestamp) obj); }
				if ("class java.lang.String".equals(genericType)) { return getTimestamp((Timestamp) obj); }
			}
			// 如果数据库裂隙为Long
			else if (obj instanceof Long)
			{
				if ("class java.lang.Integer".equals(genericType)) { return Integer.valueOf(obj.toString()); }
				if ("class java.lang.String".equals(genericType)) { return obj.toString(); }
			}
			// 如果数据库裂隙为Integer
			else if (obj instanceof Integer)
			{
				if ("class java.lang.String".equals(genericType)) { return obj.toString(); }
			}
			// 如果数据库裂隙为Integer
			else if (obj instanceof String)
			{
				if ("char".equals(genericType)) { return obj.toString().charAt(0); }
				if ("class java.lang.Integer".equals(genericType)
						&& !"".equals(obj.toString())) { return Integer.valueOf(obj.toString()); }
			}
			else if (obj instanceof java.math.BigDecimal) { return obj.toString(); }
			return obj;
		}
		return null;
	}

	public static <T> Map<Integer, String> buildColumnMap(Class<T> t, ResultSetMetaData metaData)
	{
		Set<String> fields = getDeclaredFields(t);
		Map<Integer, String> map = new HashMap<>();
		if (fields == null || fields.isEmpty()) { return map; }
		if (logger.isDebugEnabled())
		{
			logger.debug("Build object map with metadata");
		}
		try
		{
			for (String field : fields)
			{
				for (int i = 1; i < metaData.getColumnCount() + 1; i++)
				{
					if (field.equals(metaData.getColumnLabel(i)) || field.equals(metaData.getColumnName(i))
							|| field.equals(ConvertName(metaData.getColumnLabel(i)))
							|| field.equals(ConvertName(metaData.getColumnName(i))))
					{
						map.put(i, field);
						break;
					}
				}
			}
		}
		catch (SQLException e)
		{
			logger.error("获取对象和数据库的映射失败", e);
		}
		return map;
	}

	public static String ConvertName(String name)
	{
		name = name.toLowerCase();
		String[] strs = name.split("_");
		StringBuffer sb = new StringBuffer();
		for (int i = 0; i < strs.length; i++)
		{
			if (i == 0)
			{
				sb.append(strs[i]);
			}
			else
			{
				char[] c = strs[i].toCharArray();
				for (int j = 0; j < c.length; j++)
				{
					if (j == 0)
					{
						sb.append((c[j] + "").toUpperCase());
					}
					else
					{
						sb.append(c[j]);
					}
				}
			}
		}
		return sb.toString();
	}

	public static TableStruct buildSQLMap(Object obj, SQLType sqlType)
	{
		TableStruct tableStruct = ReflectJPA.getTable(obj);
		if (tableStruct == null || tableStruct.getTableName() == null)
		{
			logger.error("解析对象的注解失败 => " + obj.getClass().getName());
			return null;
		}

		switch (sqlType)
		{
		case INSERT:
			tableStruct.setBuildMap(getInsertSQL(tableStruct));
			break;
		case UPDATE:
			tableStruct.setBuildMap(getUpdateSQL(tableStruct));
			break;
		case UPDATENOTNULL:
			tableStruct.setBuildMap(getUpdateNotNullSQL(tableStruct));
			break;
		case DELETE:
			tableStruct.setBuildMap(getDeleteSQL(tableStruct));
			break;
		default:
			break;
		}
		return tableStruct;
	}

	private static Map<Integer, Object> getDeleteSQL(TableStruct tableStruct)
	{
		Map<Integer, Object> map = new HashMap<Integer, Object>();
		try
		{
			Map<String, Object> columns = tableStruct.getColumns();
			StringBuffer sql1 = new StringBuffer();
			Set<String> keys = columns.keySet();
			int j = 1;
			Object obj = null;
			for (String key : keys)
			{
				obj = columns.get(key);
				if (obj != null)
				{
					sql1.append(key + "=? AND ");
					map.put(j, obj);
					j++;
				}
			}
			if (j > 1)
			{
				sql1.delete(sql1.length() - 5, sql1.length());
			}
			String sql = "delete from " + tableStruct.getTableName() + " where " + sql1.toString();
			if (logger.isDebugEnabled())
			{
				logger.debug("构造完成的SQL => " + sql);
			}
			map.put(0, sql);
		}
		catch (Exception e)
		{
			logger.error("构造DELETE语句失败", e);
		}
		return map;
	}

	private static Map<Integer, Object> getUpdateNotNullSQL(TableStruct tableStruct)
	{
		Map<Integer, Object> map = new HashMap<Integer, Object>();
		try
		{
			Map<String, Object> columns = tableStruct.getColumns();
			String primaryKey = tableStruct.getPrimaryKey();

			StringBuffer sql1 = new StringBuffer(" set ");
			Set<String> keys = columns.keySet();
			int j = 1;
			Object obj = null;
			for (String key : keys)
			{
				obj = columns.get(key);
				if (!key.equals(primaryKey) && obj != null)
				{
					sql1.append(key + "=?,");
					map.put(j, obj);
					j++;
				}
			}
			sql1.deleteCharAt(sql1.length() - 1);
			StringBuffer sql2 = new StringBuffer(primaryKey + " = ?");
			map.put(j, columns.get(primaryKey));
			String sql = "update " + tableStruct.getTableName() + sql1.toString() + " where " + sql2.toString();
			if (logger.isDebugEnabled())
			{
				logger.debug("构造完成的SQL => " + sql);
			}
			map.put(0, sql);
		}
		catch (Exception e)
		{
			logger.error("构造UPDATE语句失败", e);
		}
		return map;
	}

	private static Map<Integer, Object> getUpdateSQL(TableStruct tableStruct)
	{
		Map<Integer, Object> map = new HashMap<Integer, Object>();
		try
		{
			Map<String, Object> columns = tableStruct.getColumns();
			String primaryKey = tableStruct.getPrimaryKey();

			StringBuffer sql1 = new StringBuffer(" set ");
			Set<String> keys = columns.keySet();
			int j = 1;
			for (String key : keys)
			{
				if (!key.equals(primaryKey))
				{
					sql1.append(key + "=?,");
					map.put(j, columns.get(key));
					j++;
				}
			}
			sql1.deleteCharAt(sql1.length() - 1);
			StringBuffer sql2 = new StringBuffer(primaryKey + " = ?");
			map.put(j, columns.get(primaryKey));
			String sql = "update " + tableStruct.getTableName() + sql1.toString() + " where " + sql2.toString();
			if (logger.isDebugEnabled())
			{
				logger.debug("构造完成的SQL => " + sql);
			}
			map.put(0, sql);
		}
		catch (Exception e)
		{
			logger.error("构造UPDATE语句失败", e);
		}
		return map;
	}

	private static Map<Integer, Object> getInsertSQL(TableStruct tableStruct)
	{
		Map<Integer, Object> map = new HashMap<Integer, Object>();
		try
		{
			Map<String, Object> columns = tableStruct.getColumns();
			String generageKey = tableStruct.getGenerateKey();

			StringBuffer sql1 = new StringBuffer("(");
			StringBuffer sql2 = new StringBuffer("(");
			Set<String> keys = columns.keySet();
			int j = 1;
			Object obj = null;
			for (String key : keys)
			{
				obj = columns.get(key);
				if (!key.equals(generageKey) && obj != null)
				{
					sql1.append(key + ",");
					sql2.append("?,");
					map.put(j, obj);
					j++;
				}
			}
			sql1.deleteCharAt(sql1.length() - 1);
			sql1.append(")");
			sql2.deleteCharAt(sql2.length() - 1);
			sql2.append(")");
			String sql = "insert into " + tableStruct.getTableName() + sql1.toString() + " values " + sql2.toString();
			if (logger.isDebugEnabled())
			{
				logger.debug("构造完成的SQL => " + sql);
			}
			map.put(0, sql);
		}
		catch (Exception e)
		{
			logger.error("构造Insert语句失败", e);
		}
		return map;
	}

	public static void setValue(Object obj, String memberName, Object value)
	{
		try
		{
			String declaredName = ConvertName(memberName);
			Field field = obj.getClass().getDeclaredField(declaredName);
			field.setAccessible(true);
			field.set(obj, value);
		}
		catch (Exception e)
		{
			logger.error("对主键赋值失败 => " + memberName, e);
		}
	}

	public static <T> Set<String> getDeclaredFields(Class<T> t)
	{
		Set<String> fieldList = new HashSet<String>();
		Field[] fields = t.getDeclaredFields();
		for (Field field : fields)
		{
			fieldList.add(field.getName());
		}
		getDeclaredFields(t.getSuperclass(), fieldList);
		return fieldList;
	}

	private static void getDeclaredFields(Class<?> superclass, Set<String> fieldList)
	{
		if (superclass != null)
		{
			Field[] fields = superclass.getDeclaredFields();
			for (Field field : fields)
			{
				fieldList.add(field.getName());
			}
			getDeclaredFields(superclass.getSuperclass(), fieldList);
		}
	}
}
